﻿using Nemerle;
using Nemerle.Collections;
using Nemerle.Text;
using Nemerle.Utility;

using System;
using System.Console;
using System.Collections.Generic;
using System.Linq;

using Microsoft.Cci;

using Nemerle2.Compiler;

namespace MetadataReader.CCI
{
  internal class CciReferencedAssembly : IReferencedAssembly
  {
    internal  _cciAssembly   : IAssembly;
              _provider      : CciMetadataProvider;
    mutable   _allTypesArray : array[CciTypeInfo] = array[];
    mutable   _initialized   : bool;
    
    public this(assembly : IAssembly, provider : CciMetadataProvider)
    {
      _cciAssembly  = assembly;
      _provider     = provider;
      FullName      = UnitHelper.StrongName(assembly : IAssemblyReference);
      ImagePath     = assembly.AssemblyIdentity.Location;
      Flags         = assembly.Flags :> AssemblyNameFlags;
      
      _ = Changed;
    }
    
    internal CciAssembly : IAssembly { get { _cciAssembly } }

    //internal AddMessage( msg : Msg) : void
    //{
    //  Msgs ::= msg;
    //}

    public CustomAttributes  : ICustomAttributes
    {
      [Memoize]
      get
      {
        CciCustomAttributes(_provider, _cciAssembly.Attributes)
      }
    }

    /// <summary>
    /// Sequence of namespace types
    /// </summary>
    public TopLevelTypes : Seq[ITypeInfo]
    {
      [Memoize] get { _allTypesArray.Where(t => t.DeclaringType == null).NToArray() }
    }

    /// <summary>Sequence of all types</summary>
    public AllTypes          : Seq[ITypeInfo]    { get { _allTypesArray } }
    
    public LookupType(_name : string, _typeParamsCount : int) : ITypeInfo
    {
      throw NotImplementedException()
    }

    // TODO: тут надо бросать ObjectDisposedException или AssemblyNotInitializedExceprion,
    // с проверкой соответсвующего условия!!!
    //CustomAttributes  : ICustomAttributes { get; }
    //TopLevelTypes     : Seq[NTypeInfo]    { get; }
    //AllTypes          : Seq[NTypeInfo]    { get; }
    //Macros            : Seq[IMacro2]      { get; }
    
    public Macros            : Seq[IMacro2]      { get; private set; }
    public Msgs              : list[Msg]         { get; private set; }
    public ImagePath         : string            { get; private set; }
    public FullName          : string            { get; private set; }
    public Name              : string            { get { _cciAssembly.Name.Value } }
    public Flags             : AssemblyNameFlags { get; private set; }

    public event Changed : EventHandler;
    
    public Init() : void
    {
      unless (_initialized)
      {        
        _initialized = true;
        //WriteLine($"  $(Threading.Thread.CurrentThread.ManagedThreadId) $(Name)");
        _allTypesArray = _provider.AddTypeInfos(_cciAssembly.GetAllTypes(), this);
      }
    }

    public override ToString() : string
    {
    	$"Assembly: $Name"
    }
  }
}
